<template>
  <div class="filter-date-range">
    <div class="header">
      <span
        v-for="tab in tabData"
        :key="tab.key"
        :class="{ tabs: true, active: activeKey === tab.key }"
        @click="toggleTabKey(tab)"
      >
        {{ tab.name }}
      </span>
    </div>

    <div class="content">
      {{ tips }}
      <a-date-picker
        class="input-min"
        :disabled="activeKey === '<='"
        :value="inputMinValue"
        size="small"
        :disabled-date="(current) => disabledDate(current, 'min')"
        :allow-clear="false"
        @change="(date, dateString) => onDateChange(date, dateString, 'min')"
      />
      <a-date-picker
        class="input-max"
        :disabled="activeKey === '>='"
        :value="inputMaxValue"
        size="small"
        :disabled-date="(current) => disabledDate(current, 'max')"
        :allow-clear="false"
        @change="(date, dateString) => onDateChange(date, dateString, 'max')"
      />
      <vue-slider
        v-model="value"
        class="slider"
        :min="min"
        :max="max"
        tooltip="none"
        :direction="sliderDirection"
        @change="onSliderChange"
        @drag-start="onSliderDragStart"
        @drag-end="emitFilterParams"
      />
      <a-checkbox :checked="nullChecked" @change="toggleNullChecked($event)"
        >包含null值</a-checkbox
      >
    </div>
  </div>
</template>

<script lang="ts">
import { Vue, Component, Prop, Watch } from 'vue-property-decorator'
import { apiGetColumnStat } from '@/api/data-clean'
import { IColumn, IKeyValueStore } from '@/store/modules/dataview'
import { ColumnStat } from '@/components/studio/data/node-edit-panel/interface'
import { StatisticsAction } from '@/util/data-selection-actions'
import VueSlider from 'vue-slider-component'
import moment, { Moment } from 'moment'
import 'vue-slider-component/theme/default.css'

const filterTypeMapping = {
  between: '[a,b]',
  greater: '>=',
  lighter: '<=',
}

@Component({
  components: {
    VueSlider,
  },
})
export default class FilterDateRange extends Vue {
  @Prop() requestParams: any
  @Prop() column!: IColumn
  @Prop() columnStat!: ColumnStat
  @Prop() editData!: any
  @Prop({ default: false }) isEdit!: boolean
  @Prop({ default: '' }) parentTableName!: boolean
  private activeKey: '[a,b]' | '<=' | '>=' = '[a,b]'
  private min: number = 0
  private max: number = 2
  private value: number | number[] = 0
  private sliderDirection: 'ltr' | 'rtl' = 'ltr'
  private nullChecked: boolean = false
  private sliderDrag: boolean = false
  private dateFormat: string = 'YYYY-MM-DD 00:00:00'

  private tabData: any = [
    {
      name: '范围', // 范围区间
      key: filterTypeMapping.between,
    },
    {
      name: '大于',
      key: filterTypeMapping.greater,
    },
    {
      name: '小于',
      key: filterTypeMapping.lighter,
    },
  ]
  private get tips(): string {
    let tips = ''
    switch (this.activeKey) {
      case filterTypeMapping.between:
        tips = '只包括此范围中的值'
        break
      case filterTypeMapping.greater:
        tips = '只包括>=最小值的值'
        break
      case filterTypeMapping.lighter:
        tips = '只包括<=最大值的值'
        break
      default:
        break
    }
    return tips
  }

  private onSliderChange() {
    if (this.sliderDrag) {
      // 拖拽中改变的值抛弃
      return
    }
    this.emitFilterParams()
  }

  private onSliderDragStart() {
    this.sliderDrag = true
  }

  private get inputMinValue() {
    let value = 0
    if (this.activeKey === filterTypeMapping.between) {
      ;[value] = this.value as number[]
    } else if (this.activeKey === filterTypeMapping.lighter) {
      value = this.min
    } else {
      value = this.max - (this.value as number) + this.min
    }
    return moment(value)
  }

  private get inputMaxValue() {
    let value = 0
    if (this.activeKey === filterTypeMapping.between) {
      ;[, value] = this.value as number[]
    } else if (this.activeKey === filterTypeMapping.greater) {
      value = this.max
    } else {
      value = this.value as number
    }
    return moment(value)
  }

  /**
   * 格式化抛出去的参数值
   */
  private get formatParamsValue() {
    let value = []
    const inputMaxValue = this.inputMaxValue.format(this.dateFormat)
    const inputMinValue = this.inputMinValue.format(this.dateFormat)
    if (this.activeKey === filterTypeMapping.between) {
      value = [`${inputMinValue}`, `${inputMaxValue}`]
    } else if (this.activeKey === filterTypeMapping.greater) {
      value = [`${inputMinValue}`]
    } else {
      value = [`${inputMaxValue}`]
    }

    return value
  }

  /**
   * 格式化抛出去的描述
   */
  private get formatDescription() {
    let description = ''
    const inputMaxValue = this.inputMaxValue.format(this.dateFormat)
    const inputMinValue = this.inputMinValue.format(this.dateFormat)

    if (this.activeKey === filterTypeMapping.between) {
      description = `${inputMinValue} 至 ${inputMaxValue}`
    } else if (this.activeKey === filterTypeMapping.greater) {
      description = `值≥${inputMinValue}`
    } else {
      description = `值≤${inputMaxValue}`
    }
    if (this.nullChecked) {
      // 包含null值
      description += '(包含null值)'
    }
    return description
  }

  @Watch('columnStat', { immediate: true, deep: true })
  private onColumnStatChange(newValue: ColumnStat) {
    if (!newValue) {
      return
    }
    if (!this.isEdit) {
      this.min = +new Date(newValue.min)
      this.max = +new Date(newValue.max)
      this.setSliderValue()
    }
  }

  @Watch('editData', { immediate: true, deep: true })
  private onCurrentHistoryChange(newValue: IKeyValueStore) {
    if (!newValue || !this.isEdit) {
      return
    }
    const history = newValue.data
    if (
      history.actionType === StatisticsAction.filterDateRange &&
      history.col === this.column.name
    ) {
      const data = history.filter[0][0]
      this.activeKey = data.filterType
      this.value = data.values.map((item: string) => +new Date(item))
      if (
        history.filter[0].length > 1 &&
        history.filter[0][1].values[0] === '#NULL'
      ) {
        // 包含null值
        this.nullChecked = true
      }
      this.getLastHistoryColumnData()
    }
  }

  /**
   * 编辑模式下需要根据上一个记录的表名来查询数据
   */
  async getLastHistoryColumnData() {
    /* eslint-disable unicorn/prevent-abbreviations */
    const requestParams = this.requestParams || {}
    if (this.isEdit) {
      // 编辑模式下，获取的选项是基于上一个记录的表进行查询
      requestParams.table = this.parentTableName // 编辑状态下是基于上一条记录的表名来进行筛选
    }
    const response = await apiGetColumnStat({
      data: {
        ...requestParams,
      },
    })
    if (!response.data.success) {
      return
    }
    const { result } = response.data
    this.min = +new Date(result.min)
    this.max = +new Date(result.max)
    if (this.activeKey === filterTypeMapping.greater) {
      this.sliderDirection = 'rtl'
      this.value = this.max - (this.value as number[])[0] + this.min
    } else if (this.activeKey === filterTypeMapping.lighter) {
      ;[this.value] = this.value as number[]
    }
  }

  /**
   * 设置slider的值
   */
  setSliderValue() {
    this.sliderDirection = 'ltr'
    if (this.activeKey === filterTypeMapping.between) {
      this.value = [this.min, this.max]
    } else if (this.activeKey === filterTypeMapping.greater) {
      this.value = this.max
      this.sliderDirection = 'rtl'
    } else {
      this.value = this.max
    }
  }

  toggleTabKey(tab: any) {
    this.activeKey = tab.key
    this.setSliderValue()
    this.emitFilterParams()
  }

  /**
   * 是否包含null值
   */
  toggleNullChecked(event: any) {
    const { checked } = event.target
    this.nullChecked = checked
    this.emitFilterParams()
  }

  /**
   * 抛出去filter参数
   */
  emitFilterParams() {
    this.sliderDrag = false
    const filter: any = [
      // 抛出最终用于筛选的选项值
      [
        {
          col: this.column.name,
          filterType: this.activeKey,
          values: this.formatParamsValue,
        },
      ],
    ]
    if (this.nullChecked) {
      // 包含null值
      filter[0].push({
        col: this.column.name,
        filterType: '=',
        values: ['#NULL'],
      })
    }
    this.$emit('on-filter-params-change', {
      data: {
        action: 'FILTER',
        col: this.column.name,
        filter,
        description: this.formatDescription,
        actionType: StatisticsAction.filterDateRange,
      },
    })
  }
  /**
   * 设置不可选的日期范围
   */
  private disabledDate(current: Moment, type: 'min' | 'max') {
    if (!current) {
      return true
    }
    if (type === 'min') {
      // 范围起点选择框的可选范围
      return current < moment(this.min) || current > this.inputMaxValue
    }
    if (type === 'max') {
      // 范围终点选择框的可选范围
      return current < this.inputMinValue || current > moment(this.max)
    }
    return false
  }

  /**
   * 日期选择器选择后调整数据
   */
  private onDateChange(
    date: Moment | string,
    dateString: string,
    type: 'min' | 'max'
  ) {
    const value = +new Date(dateString)
    if (value < this.min || value > this.max) {
      return
    }

    if (this.activeKey === filterTypeMapping.between) {
      this.$set(this.value as number[], type === 'min' ? 0 : 1, value)
    } else if (this.activeKey === filterTypeMapping.greater) {
      this.value = this.max - value + this.min
    } else {
      this.value = value
    }
    this.emitFilterParams()
  }
}
</script>

<style lang="less" scoped>
.filter-date-range {
  .header {
    align-items: center;
    background-color: #fff;
    border-bottom: 1px solid rgba(233, 233, 233, 0.8);
    color: #373b52;
    display: flex;
    font-size: 14px;
    height: 25px;
    justify-content: space-between;
    line-height: 26px;
    width: 100%;

    .tabs {
      cursor: pointer;
      display: inline-block;
      height: 25px;
      margin-right: 8px;
      padding: 0 12px;

      &.active {
        border-bottom: 2px solid #5963e5;
        color: #5963e5;
        font-weight: 500;
      }
    }
  }

  .content {
    margin-top: 24px;

    .input-min,
    .input-max {
      margin-top: 8px;
      width: 48%;
    }

    .input-min {
      margin-right: 6px;
    }

    .slider {
      margin: 12px 5px;
    }

    /deep/ .vue-slider-process {
      background-color: #5963e5;
    }

    /deep/ .vue-slider-dot-handle-focus {
      box-shadow: 0 0 1px 2px rgba(89, 99, 229, 0.36);
    }

    /deep/ .ant-input {
      font-size: 12px;
    }
  }
}
</style>
